package com.linshengjian.power.service.imp;

import com.google.common.collect.Multimap;
import com.linshengjian.core.BaseDao;
import com.linshengjian.core.BaseService;
import com.linshengjian.core.BusinessException;
import com.linshengjian.power.dao.ResourcesDao;
import com.linshengjian.power.entity.ResourcesEntity;
import com.linshengjian.power.model.Resources;
import com.linshengjian.power.service.IResourcesService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import springfox.documentation.service.ApiDescription;
import springfox.documentation.service.ApiListing;
import springfox.documentation.service.Documentation;
import springfox.documentation.service.Operation;
import springfox.documentation.spring.web.DocumentationCache;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

@Service
public class ResourcesService extends BaseService<ResourcesEntity, Resources, Integer> implements IResourcesService {

    @Autowired
    private ResourcesDao resourcesDao;

    @Autowired
    private DocumentationCache documentationCache;

    private List<ApiDescription> getApiDescriptions() {
        Documentation documentation = documentationCache.documentationByGroup(Docket.DEFAULT_GROUP_NAME);
        Multimap<String, ApiListing> apiListing = documentation.getApiListings();
        List<ApiDescription> result = new ArrayList<>();
        for (ApiListing api: apiListing.values()) {
            result.addAll(api.getApis());
        }
        return result;
    }

    private void disableAll(){
        List<ResourcesEntity> list = (List<ResourcesEntity>) resourcesDao.findAll();
        for (ResourcesEntity res: list) {
            res.setUsable(false);
        }

        resourcesDao.save(list);
    }

    /**
     * 更新资源
     * @param resources
     */
    private void update(ResourcesEntity resources) {
        ResourcesEntity old = resourcesDao.findByPathAndValidIsTrue(resources.getPath());
        if (old != null) {
            resources.setId(old.getId());
        }
        resources.setUsable(true);
        resourcesDao.save(resources);
    }

    @Override
    @Transactional(rollbackFor = Exception.class )
    public void refresh() {
        disableAll();
        List<ApiDescription> result = getApiDescriptions();
        for (ApiDescription api: result) {
            for (Operation operation: api.getOperations()) {
                ResourcesEntity resource = new ResourcesEntity()
                        .setPath(operation.getMethod().name() + ":" + api.getPath())
                        .setSummary(operation.getSummary())
                        .setDescription(operation.getNotes());

                update(resource);
            }
        }
    }

    @Override
    protected BaseDao<ResourcesEntity, Integer> dao() {
        return resourcesDao;
    }

    @Override
    protected ResourcesEntity model2Entity(Resources model) {
        ResourcesEntity entity = new ResourcesEntity();
        entity.setId(model.getId());
        entity.setPath(model.getPath())
                .setSummary(model.getSummary())
                .setDescription(model.getDescription())
                .setUsable(model.getUsable());
        return entity;
    }

    @Override
    protected Resources entity2model(ResourcesEntity entity) {
        Resources model = new Resources();
        model.setId(entity.getId());
        model.setPath(entity.getPath())
                .setSummary(entity.getSummary())
                .setDescription(entity.getDescription())
                .setUsable(entity.getUsable());
        return model;
    }

    @Override
    protected List<Resources> entity2Model(Collection<ResourcesEntity> list) {
        return super.entity2Model(list);
    }

    @Override
    public Resources add(Resources model) throws BusinessException {
        throw new BusinessException("This method can only be used");
    }

    @Override
    public Resources update(Resources model) throws BusinessException {
        throw new BusinessException("This method can only be used");
    }

    @Override
    public void delete(Integer integer) throws BusinessException {
        throw new BusinessException("This method can only be used");
    }

    @Override
    public void delete(Resources model) throws BusinessException {
        throw new BusinessException("This method can only be used");
    }
}
